﻿/**
 * author:  Martin Hrabos
 * year:    2016
 * email:   hrabosmartin@gmail.com
 * 
 * FIT Brno University of Technology / ASCR Brno
 */

using Cloo;
using ManagedCuda;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CorrCL
{
    /*
     * Class related to computations
     */
    abstract class Computation
    {

        protected long offset;
        protected long size;
        protected List<List<float>> data;
        protected List<string> labels;

        protected int platformID;
        public Boolean cudaSelected;
        protected ResultMatrix rm;
        public int THREADS_COUNT = 16;
        public float frequency;
        public long windowSize;
        public long windowOffset;
        public string sourceFile;

        public event ProgressChangedEventHandler ProgressChanged;

        // Function for sending on progress changed events
        protected virtual void OnProgressChanged(int progress, string status)
        {
            if (ProgressChanged != null)
            {
                ProgressChanged(this, new System.ComponentModel.ProgressChangedEventArgs(progress, status));
            }
        }


        public Computation()
        {

        }

        // Function for detecting CUDA device
        public static Boolean checkCUDA()
        {
            Boolean available = false;
            try
            {
                CudaContext Context = new CudaContext(CudaContext.GetMaxGflopsDeviceId());
                available = File.Exists(@"plugins/pearson.ptx");
            } catch (Exception e)
            {
                available = false;
            }
            return available;
        }

        // Function for obtaining list of OpenCL devices
        public static object[] getPlatforms()
        {
            List<object> items = new List<object>();
            int count = 0;
            try
            {
                count = ComputePlatform.Platforms.Count;


                for (int i = 0; i < count; i++)
                {
                    string platInfo;
                    platInfo = ComputePlatform.Platforms[i].Vendor;
                    platInfo += " " + ComputePlatform.Platforms[i].Devices[0].Name;
                    items.Add(platInfo);
                }
            }
            catch (System.TypeInitializationException e)
            {
                return items.ToArray();
            }

            return items.ToArray();
        }

        // Function for obtaining max single buffer allocation size
        public static long getMaxDevObjectMemoryAllocationSize(int device)
        {
            return ComputePlatform.Platforms[device].Devices[0].MaxMemoryAllocationSize;
        }

        // Function for obtaining total device memory size
        public static long getMaxDevGlobalMemSize(int device)
        {
            return ComputePlatform.Platforms[device].Devices[0].GlobalMemorySize;
        }

        // Function for returning results
        public ResultMatrix getResults()
        {
            return this.rm;
        }

        // Function for setting results
        public void setResults(ResultMatrix rm)
        {
            this.rm = rm;
        }

        // Function for setting data to be processed
        public void setData(List<List<float>> d, List<string> labelList)
        {
            this.data = d;
            // Get size of channels
            size = d[0].Count;
            Debug.WriteLine("Setting size "+size);
            rm = new ResultMatrix(labelList, frequency);
            rm.size = size;
            rm.windowOffset = windowOffset;
            rm.windowSize = windowSize;
            rm.sourceFile = sourceFile;
        }

        // Funcstion for setting offset
        public void setOffset(long value)
        {
            this.offset = value;
        }

        // Abstract function for running computation
        public abstract void compute();

    }
    delegate void ValueChangedEventHandler(bool value);
}
